let Vue = null
class Store{
    constructor(options){
        this.options = options
        this.mutations = options.mutations
        this.actions = options.actions

        // getter简单实现
        const _getters = options.getters
        const computed = {}
        this.getters = {}
        
        Object.keys(_getters).forEach((key)=>{
            computed[key] = ()=>{
                // 箭头函数让里面的this指向store实例。用匿名函数的话this指向会错误。
                return _getters[key](this.state)
            }
            Object.defineProperty(this.getters, key, {
                get:() => {
                    // 箭头函数让里面的this指向store实例。用匿名函数的话this指向会错误。
                    return this._vm[key]
                }
            })
        })

        // this.state = options.state
        // 把options.state变成响应式
        this._vm = new Vue({
            data:{
                // Vue内部处理机制，添加$$则改值不会被Vue代理，即不能通过vm.$$state的方式访问到，必须通过 vm._data.$$state 访问
                $$state: options.state
            },
            computed
        })

        // 直接绑死，以免用户调用时上下文改变，例如在定时器里调用commit，这样就会造成commit方法内部this指向改变
        this.commit = this.commit.bind(this)
        this.dispatch = this.dispatch.bind(this)
    }
    // 这么做是为了隐藏state，不让用户直接访问到或直接改变它
    get state(){
       return this._vm.$data.$$state
    }
    set state(v){
        console.error('不能直接设置state')
    }
  
    commit(type,payLoad){
        const fn = this.mutations[type]
        if(fn){
            fn(this.state,payLoad)
        }else{
            console.error('未声明此类型的mutations')
        }
    }

    dispatch(type,payLoad){
        const fn = this.actions[type]
        if(fn){
            fn(this,payLoad)
        }else{
            console.error('未声明此类型的actions')
        }
    }

}

function install(_Vue){
    Vue = _Vue
    Vue.mixin({
        beforeCreate(){
            if(this.$options.store){
                Vue.prototype.$store = this.$options.store
            }
        }
    })
}

export default {
    Store,
    install
}